package com.atguigu.ucenter_member.controller;
import com.atguigu.commonutils.exceptionhandler.GuliException;
import com.atguigu.commonutils.jwt.JwtUtils;
import com.atguigu.ucenter_member.entity.UcenterMemberEntity;
import com.atguigu.ucenter_member.service.UcenterMemberService;
import com.atguigu.ucenter_member.utils.ConstanWxtiesUtil;
import com.atguigu.ucenter_member.utils.HttpClientUtils;
import com.google.gson.Gson;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.net.URLEncoder;
import java.util.HashMap;

/**
 * @description:
 * @author: Administrator
 * @date: 2021-04-14 23:33
 */
@CrossOrigin
@Controller//注意这里没有配置 @RestController
@RequestMapping("/api/ucenter/wx")
@Api(tags = "--前台微信扫码登录接口API")
public class WeChatApi {
    @Autowired
    private UcenterMemberService ucenterMemberService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 第三方使用网站应用授权登录前请注意已获取相应网页授权作用域（scope=snsapi_login），
     * 则可以通过在PC端打开以下链接： https://open.weixin.qq.com/connect/qrconnect
     * ?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&s
     * tate=STATE#wechat_redirect 若提示“该链接无法访问”，请检查参数是否填写错误，
     * 如redirect_uri的域名与审核时填写的授权域名不一致或scope不为snsapi_login。
     * 微信开放平台授权baseUrl
     * 请使用urlEncode对redirect_uri进行处理
     * <p>
     * 下面这个是完整拼接可以用，basrurl+appid+redirect_url+scope权限
     * https://open.weixin.qq.com/connect/qrconnect?appid=wxed9954c01bb89b47&redirect_uri=
     * http://guli.shop/api/ucenter/wx/callback&scope=snsapi_login&&state="atguigu"
     * <p>
     * 页面接口访问：http://localhost:8006/api/ucenter/wx/login
     */
    @ApiOperation(value = "用户登录", notes = "http://localhost:8150/api/ucenter/wx/login")
    @GetMapping("/login")
    public String getWxApi() {
        String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
                "?appid=%s" +
                "&redirect_uri=%s" +
                "&response_type=code" +
                "&scope=snsapi_login" +
                "&state=%s" +
                "#wechat_redirect";

        // 回调地址
        String redirectUrl = ConstanWxtiesUtil.WX_OPEN_REDIRECT_URL; //获取业务服务器重定向地址
        try {
            redirectUrl = URLEncoder.encode(redirectUrl, "utf-8"); //url编码
        } catch (Exception e) {
            e.printStackTrace();
        }

        //生成qrcodeUrl
        String finalUrl = String.format(
                baseUrl,
                ConstanWxtiesUtil.WX_OPEN_APP_ID,
                redirectUrl,
                "atguigu");
        return "redirect:" + finalUrl;
    }

    /**
     * 通过统一请求地址callback，他自己改的跳转路径
     * redirect:http://localhost:3000固定地址
     * 1、扫码登录，点击确认
     * 2、通过code临时票据获取用户信息
     * 3、HttpClientUtils用户端请求服务器，前台都是返回字符串，转换一下
     * 这个工具大概意思就是通过浏览器获取信息（前台获取前台信息，只不过用的IOUtils流的方式获取，意思就是可以获取字节码字符码，文件图片都可以）
     * 测试方式：
     * 1、swagger请求login接口，把返回的地址放入浏览器中，显示出一个二维码
     * 2、客户端扫描，确认登录，浏览器地址中返回code和state两个参数
     * 3、复制两个参数请求callback接口，控制台返回一个json字符串，可以放在在线json解析器里面看他的结构
     * 4、下面我就不写详细注释了，具体参数看wx开发者文档，只写步骤
     *
     * @param code
     * @param state
     * @return
     */
    @ApiOperation(value = "扫码", notes = "atguigu")
    @GetMapping("/callback")
    public String callback(String code, String state) {
        try {
            //1、扫码获取临时票据code，baseAccessTokenUrl固定地址，拼接地址，这里相当于认证
            String baseAccessTokenUrl =
                    "https://api.weixin.qq.com/sns/oauth2/access_token" +
                            "?appid=%s" +
                            "&secret=%s" +
                            "&code=%s" +
                            "&grant_type=authorization_code";

            String finalUrl = String.format(
                    baseAccessTokenUrl,
                    ConstanWxtiesUtil.WX_OPEN_APP_ID,
                    ConstanWxtiesUtil.WX_OPEN_APP_SECRET,
                    code
            );
            //2、获取access_token和openid，拼接参数获取用户基本信息，这里相当于授权成功，访问隐私内容
            //认证加授权，后面都是这个思路
            String accessTokenInfo = HttpClientUtils.get(finalUrl);
            Gson gs = new Gson();
            HashMap hashMap = gs.fromJson(accessTokenInfo, HashMap.class);
            String access_token = (String) hashMap.get("access_token");
            String openid = (String) hashMap.get("openid");
            //4、根据openid唯一性，如果没有返回值，注册加登录，有的话说明有了，直接登录
            UcenterMemberEntity user = ucenterMemberService.selectOpenId(openid);
            if (user == null) {
                String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                        "?access_token=%s" +
                        "&openid=%s";
                String userInfoUrl = String.format(
                        baseUserInfoUrl,
                        access_token,
                        openid);
                //3、地址中接收数据字符串类型，用gson转化成hashmap形式的json字符串
                String userInfo = HttpClientUtils.get(userInfoUrl);
                HashMap hashMapUserInfo = gs.fromJson(userInfo, HashMap.class);

                String nickname = (String) hashMapUserInfo.get("nickname");
                String headimgurl = (String) hashMapUserInfo.get("headimgurl");
                user = new UcenterMemberEntity();
                user.setNickname(nickname);
                user.setAvatar(headimgurl);
                user.setOpenid(openid);
                System.out.println(userInfo);
                System.out.println(hashMapUserInfo);
                ucenterMemberService.save(user);
            }
            String jwtToken = JwtUtils.getJwtToken(user.getId(), user.getNickname());
            return "redirect:http://localhost:3000?token=" + jwtToken;
        } catch (Exception e) {
            e.printStackTrace();
            throw new GuliException(20001, "登录失败");
        }
    }
}
          //5、返回参数测试
          /**
           * 总结：就是个认证授权的过程
           * 通过扫码，获取票据code，根据code获取认证token，获取access_token和openid,再根据参数获取用户信息，拼接的基础url都是固定地址
           * 举例出来的都是最主要的参数，其他可看wx文档，这里建议通过文档中错误返回样例代码，catch返回相应错误信息，用户提示会好点，我这里不改了。
           */

